﻿namespace DatabaseGroup.SSIS.SourceAdapters.Parser
{
    /// <summary>
    /// A helper class which will parse a delimited file based on the 
    /// delimited settings passed to it
    /// </summary>
    internal class DelimitedFileParser
    {
        private string _rowDelimiter = string.Empty;
        private string _columnDelimiter = string.Empty;
        private RowParser _rowParser;

        /// <summary>
        /// Initializes a new instance of the DelimitedFileParser class 
        /// using the specified delimiters
        /// </summary>
        /// <param name="columnDelimiter">The delimiter used to split the column values</param>
        /// <param name="rowDelimiter">The delimiter used to split the rows</param>
        public DelimitedFileParser(string columnDelimiter, string rowDelimiter)
        {
            ArgumentVerifier.CheckStringArgument(rowDelimiter, "rowDelimiter");

            _columnDelimiter = columnDelimiter;
            _rowDelimiter = rowDelimiter;
            this.HeaderRowDelimiter = string.Empty;
            this.HeaderRowsToSkip = 0;
            this.DataRowsToSkip = 0;
            this.TextQualifier = string.Empty;
            this.ColumnNameInFirstRow = false;
        }

        public string RowDelimiter
        {
            get { return _rowDelimiter; }
            set { _rowDelimiter = value; }
        }

        /// <summary>
        /// Gets or sets the delimiter used to split the header rows
        /// </summary>
        public string HeaderRowDelimiter { get; set; }

        /// <summary>
        /// Gets or sets the number of header rows to skip before starting to process the file
        /// </summary>
        public int HeaderRowsToSkip { get; set; }

        /// <summary>
        /// Gets or sets the number of data rows to skip before starting to process the file
        /// </summary>
        public int DataRowsToSkip { get; set; }

        /// <summary>
        /// Gets or sets the qualifier used to encapsulate a string of text
        /// </summary>
        public string TextQualifier { get; set; }

        /// <summary>
        /// Gets or sets if the values in the first row are to be used as the column names
        /// </summary>
        public bool ColumnNameInFirstRow { get; set; }

        /// <summary>
        /// Skips past header rows based on HeaderRowsToSkip
        /// </summary>
        /// <param name="reader">The file to skip header rows on</param>
        public void SkipHeaderRows(IFileReader reader)
        {
            ArgumentVerifier.CheckObjectArgument(reader, "reader");

            if (this.HeaderRowsToSkip <= 0 || string.IsNullOrEmpty(this.HeaderRowDelimiter)) 
                return;

            FieldParser headerRowFieldParser = FieldParser.BuildParserWithSingleDelimiter(this.HeaderRowDelimiter);

            for (int i = 0; i < this.HeaderRowsToSkip; i++)
            {
                headerRowFieldParser.ParseNext(reader);
                if (reader.IsEOF)
                    break;
            }
        }

        /// <summary>
        /// Skips past any non-data rows
        /// </summary>
        /// <param name="reader">The file to skip rows on</param>
        public void SkipInitialRows(IFileReader reader)
        {
            SkipHeaderRows(reader);

            if (reader.IsEOF) 
                return;

            if (this.ColumnNameInFirstRow)
                ParseNextRow(reader, null);

            if (reader.IsEOF) 
                return;

            for (int i = 0; i < this.DataRowsToSkip; i++)
            {
                ParseNextRow(reader, null);
                if (reader.IsEOF)
                    break;
            }
        }

        /// <summary>
        /// Parses the next row in the file,
        /// populating a RowData object based on the row values
        /// </summary>
        /// <param name="reader">The file to parse</param>
        /// <param name="rowData">The RowData object to be populated with the row values</param>
        public void ParseNextRow(IFileReader reader, RowData rowData)
        {
            if (_rowParser == null)
                InitializeDataRowParsing();
            
            if (_rowParser != null)
                _rowParser.ParseNextRow(reader, rowData);
        }

        /// <summary>
        /// Initializes the internal row parser based on the settings previously provided
        /// </summary>
        private void InitializeDataRowParsing()
        {
            _rowParser = new RowParser(_columnDelimiter, RowDelimiter, this.TextQualifier);
        }
    }
}
